import React, { useEffect, useState } from 'react'
import './style.css'

export default function DragSort({dataSource}) {
  // 数据源
  const [list, setList] = useState(dataSource)
  // 拖动节点的索引
  const [dragIndex, setDragIndex] = useState(-1)
  // 是否正在拖动
  const [isDragging, setDragging] = useState(false)
  // 各项高度
  const [itemHeight, setItemHeight] = useState(0)
  // 光标跟文档顶部间距
  const [pageY, setPageY] = useState(0)
  // 节点内部垂直方向偏移
  const [offsetY, setOffsetY] = useState(0)

  // 拖动时数组中元素的移动
  const move = isDown => {
    const copy = [...list]
    const item = copy.splice(dragIndex, 1)[0]
    let index
    if (isDown) {
      index = dragIndex + 1
    } else {
      index = dragIndex - 1
    }
    copy.splice(index, 0, item)
    return copy
  }

  // 拖拽项样式
  const getDragItemStyle = index => (
    isDragging && index === dragIndex
      ? {
        background: '#eaeaea',
        transform: `translate(-10px, ${offsetY}px) scale(0.8)`
      }
      : {}
  )

  // 鼠标按下，开始手动，记录拖动项索引，光标距文档顶部间距
  const handleMouseDown = (draggingIndex, e) => {
    setDragging(true)
    setPageY(e.pageY)
    setDragIndex(draggingIndex)
  }

  // 鼠标移动，处理
  const handleMouseMove = e => {
    // 节点内偏移量
    const offsetY = e.pageY - pageY

    // 向下或向上在拖动
    if (offsetY > itemHeight && dragIndex < list.length - 1) {
      setList(move(true))
      setDragIndex(dragIndex + 1)
      setPageY(pageY + itemHeight)
    } else if (offsetY < -itemHeight && dragIndex > 0) {
      setList(move(false))
      setDragIndex(dragIndex - 1)
      setPageY(pageY - itemHeight)
    }

    setOffsetY(offsetY)
  }

  // 鼠标弹起，取消拖动
  const handleMouseUp = e => {
    setDragging(false)
  }

  // 每一项的高度
  useEffect(() => {
    const listItem = document.querySelector('.list-item')
    const itemHeight = listItem?.offsetHeight ?? 0
    setItemHeight(itemHeight)
  }, [dataSource])

  return (
    <div className="list">
      {
        list.map((item, index) => (
          <div
            className="list-item"
            key={item.id}
            onMouseDown={handleMouseDown.bind(null, index)}
            style={getDragItemStyle(index)}
          >{item.title}</div>
        ))
      }
      {
        isDragging && (
          <div
            className="cover-mask"
            onMouseMove={handleMouseMove}
            onMouseUp = {handleMouseUp}
          />
        )
      }
    </div>
  )
}
